{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DNN 回归"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "from torch.optim.lr_scheduler import StepLR\n",
    "from torch.utils.data import Dataset, DataLoader"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据集准备"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def create_toy_data(f, sample_size, std=0.25, noise=True):\n",
    "    x = np.linspace(0, 1, sample_size)\n",
    "    if noise:\n",
    "        y = f(x) + np.random.normal(scale=std, size=x.shape)\n",
    "    else:\n",
    "        y = f(x)            \n",
    "    return x, y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def f(x):\n",
    "    return np.sin(2 * np.pi * x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(100,)\n"
     ]
    }
   ],
   "source": [
    "x_train, y_train = create_toy_data(f, 100)\n",
    "x_test , y_test  = create_toy_data(f, 50)\n",
    "x_exact, y_exact = create_toy_data(f, 100, noise=False)\n",
    "print(x_train.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.scatter(x_train, y_train, facecolor='none', edgecolors='b', s=50, label='training data')\n",
    "plt.plot(x_exact, y_exact, c='g', label='$\\sin(2\\pi x)$')\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SinDataset(Dataset):\n",
    "    def __init__(self, f, sample_size=1000):\n",
    "        super().__init__()\n",
    "        self.sample_size = sample_size\n",
    "        self.f = f\n",
    "        x, y = create_toy_data(self.f, self.sample_size)\n",
    "        self.x = torch.from_numpy(x).unsqueeze(dim=-1).float()\n",
    "        self.y = torch.from_numpy(y).unsqueeze(dim=-1).float()\n",
    "        \n",
    "    def __len__(self):\n",
    "        return self.sample_size\n",
    "    \n",
    "    def __getitem__(self, index):        \n",
    "        sample = {'x': self.x[index], 'y': self.y[index]}\n",
    "        return sample\n",
    "        "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: tensor([[0.0000],\n",
      "        [0.1111],\n",
      "        [0.2222],\n",
      "        [0.3333],\n",
      "        [0.4444],\n",
      "        [0.5556],\n",
      "        [0.6667],\n",
      "        [0.7778],\n",
      "        [0.8889],\n",
      "        [1.0000]]), tensor([[ 1.7011e-01],\n",
      "        [ 7.7012e-01],\n",
      "        [ 8.1443e-01],\n",
      "        [ 1.2015e+00],\n",
      "        [-4.3859e-05],\n",
      "        [-2.3389e-01],\n",
      "        [-6.6141e-01],\n",
      "        [-4.9424e-01],\n",
      "        [-5.9243e-01],\n",
      "        [ 1.5841e-01]])\n"
     ]
    }
   ],
   "source": [
    "dataset = SinDataset(f, sample_size=10)\n",
    "dataloader = DataLoader(dataset, batch_size=10, shuffle=False)\n",
    "for i, sample in enumerate(dataloader):\n",
    "    print(f\"{i}: {sample['x']}, {sample['y']}\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 神经网络模型"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [],
   "source": [
    "class SimpleNet(nn.Module):\n",
    "    def __init__(self, layers=[1, 10, 10, 10, 1]):\n",
    "        super().__init__()\n",
    "        self.layers = layers\n",
    "        self.fcs = []\n",
    "        \n",
    "        for i in range(len(layers)-1):\n",
    "            fc = nn.Linear(self.layers[i], self.layers[i+1])\n",
    "            setattr(self, f'fc{i}', fc)\n",
    "            self._init_weights(fc)\n",
    "            self.fcs.append(fc)\n",
    "\n",
    "    def _init_weights(self, layer):\n",
    "        nn.init.xavier_normal_(layer.weight)\n",
    "        nn.init.constant_(layer.bias, 0.01)\n",
    "                    \n",
    "    def forward(self, x):\n",
    "        for i in range(len(self.fcs)-1):\n",
    "            x = self.fcs[i](x)\n",
    "            x = torch.tanh(x)\n",
    "        x = self.fcs[-1](x)\n",
    "        return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "SimpleNet(\n",
      "  (fc0): Linear(in_features=1, out_features=10, bias=True)\n",
      "  (fc1): Linear(in_features=10, out_features=10, bias=True)\n",
      "  (fc2): Linear(in_features=10, out_features=10, bias=True)\n",
      "  (fc3): Linear(in_features=10, out_features=1, bias=True)\n",
      ")\n"
     ]
    }
   ],
   "source": [
    "layers = [1, 10, 10, 10, 1]\n",
    "model = SimpleNet(layers)\n",
    "print(model)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Trainer(object):\n",
    "    def __init__(self, layers=[1, 10, 10, 10, 1]):\n",
    "        self.model = SimpleNet(layers)\n",
    "        self.criterion = nn.MSELoss()\n",
    "        self.optimizer = optim.Adam(self.model.parameters(), lr=1e-3)\n",
    "        self.scheduler = StepLR(self.optimizer, step_size=100, gamma=0.5)\n",
    "        \n",
    "        self.trainset = SinDataset(f, sample_size=1000)\n",
    "        self.trainloader = DataLoader(self.trainset, batch_size=100, shuffle=True)\n",
    "        self.validset = SinDataset(f, sample_size=100)\n",
    "        self.validloader = DataLoader(self.validset, batch_size=100, shuffle=False)\n",
    "        \n",
    "    def train(self):\n",
    "        self.model.train()\n",
    "        best_loss = 1.e10\n",
    "        losses = []\n",
    "        epochs = []\n",
    "        \n",
    "        for epoch in range(50):\n",
    "            for _, sample in enumerate(self.trainloader):   \n",
    "                y_pred = self.model(sample['x'])            \n",
    "                loss = self.criterion(y_pred, sample['y'])\n",
    "                self.optimizer.zero_grad()\n",
    "                loss.backward()\n",
    "                self.optimizer.step()\n",
    "                train_loss = loss.item()\n",
    "            self.scheduler.step()\n",
    "            \n",
    "            epochs.append(epoch)\n",
    "            losses.append(train_loss)\n",
    "            if (epoch+1) % 50 == 0:\n",
    "                valid_loss = self.validate()                \n",
    "                print(f'epoch: {epoch+1}\\ttrain_loss: {train_loss:.4e}\\tvalid_loss: {valid_loss:.4e}\\tlr: {self.scheduler.get_lr()[0]:.2e}')\n",
    "                if valid_loss < best_loss:\n",
    "                    torch.save(self.model.state_dict(), \"net.pth\")\n",
    "        plt.plot(epochs, losses, 'r-')\n",
    "        \n",
    "    def validate(self):\n",
    "        self.model.eval()\n",
    "        for _, sample in enumerate(self.validloader):\n",
    "            y_pred = self.model(sample['x'])  \n",
    "            loss = self.criterion(y_pred, sample['y'])\n",
    "            return loss.item()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 151,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "epoch: 50\ttrain_loss: 1.0878e-01\tvalid_loss: 1.2377e-01\tlr: 1.00e-03\n",
      "epoch: 100\ttrain_loss: 5.4257e-02\tvalid_loss: 7.9684e-02\tlr: 5.00e-04\n",
      "epoch: 150\ttrain_loss: 6.0672e-02\tvalid_loss: 6.8225e-02\tlr: 5.00e-04\n",
      "epoch: 200\ttrain_loss: 6.4052e-02\tvalid_loss: 6.1229e-02\tlr: 2.50e-04\n",
      "epoch: 250\ttrain_loss: 7.0237e-02\tvalid_loss: 5.8907e-02\tlr: 2.50e-04\n",
      "epoch: 300\ttrain_loss: 5.3745e-02\tvalid_loss: 5.8023e-02\tlr: 1.25e-04\n",
      "epoch: 350\ttrain_loss: 5.0696e-02\tvalid_loss: 5.7654e-02\tlr: 1.25e-04\n",
      "epoch: 400\ttrain_loss: 6.3105e-02\tvalid_loss: 5.7433e-02\tlr: 6.25e-05\n",
      "epoch: 450\ttrain_loss: 5.1472e-02\tvalid_loss: 5.7388e-02\tlr: 6.25e-05\n",
      "epoch: 500\ttrain_loss: 5.2625e-02\tvalid_loss: 5.7312e-02\tlr: 3.13e-05\n",
      "epoch: 550\ttrain_loss: 6.2503e-02\tvalid_loss: 5.7239e-02\tlr: 3.13e-05\n",
      "epoch: 600\ttrain_loss: 6.3763e-02\tvalid_loss: 5.7203e-02\tlr: 1.56e-05\n",
      "epoch: 650\ttrain_loss: 5.8681e-02\tvalid_loss: 5.7176e-02\tlr: 1.56e-05\n",
      "epoch: 700\ttrain_loss: 6.6562e-02\tvalid_loss: 5.7164e-02\tlr: 7.81e-06\n",
      "epoch: 750\ttrain_loss: 6.6974e-02\tvalid_loss: 5.7170e-02\tlr: 7.81e-06\n",
      "epoch: 800\ttrain_loss: 5.4447e-02\tvalid_loss: 5.7161e-02\tlr: 3.91e-06\n",
      "epoch: 850\ttrain_loss: 6.2559e-02\tvalid_loss: 5.7155e-02\tlr: 3.91e-06\n",
      "epoch: 900\ttrain_loss: 6.3622e-02\tvalid_loss: 5.7149e-02\tlr: 1.95e-06\n",
      "epoch: 950\ttrain_loss: 5.5967e-02\tvalid_loss: 5.7149e-02\tlr: 1.95e-06\n",
      "epoch: 1000\ttrain_loss: 6.3776e-02\tvalid_loss: 5.7148e-02\tlr: 9.77e-07\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "trainer = Trainer()\n",
    "trainer.train()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 测试器"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Tester(object):\n",
    "    def __init__(self, layers=[1, 10, 10, 10, 1]):\n",
    "        self.model = SimpleNet(layers)\n",
    "        self.criterion = nn.MSELoss()\n",
    "        self.testset = SinDataset(f, sample_size=100)\n",
    "        self.testloader = DataLoader(self.testset, batch_size=100, shuffle=False)\n",
    "        \n",
    "    def test(self, model_path='net.pth'):\n",
    "        # load model parameters\n",
    "        model_params = torch.load(model_path)\n",
    "        self.model.load_state_dict(model_params)\n",
    "        \n",
    "        self.model.eval()\n",
    "        for _, sample in enumerate(self.testloader):\n",
    "            y_pred = self.model(sample['x'])\n",
    "            plt.scatter(sample['x'].numpy(), sample['y'].numpy(), fc='b', label='noise data')\n",
    "            plt.plot(sample['x'].numpy(), y_pred.detach().numpy(), c='r', label='prediction')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAD4CAYAAADvsV2wAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nO3deZxd8/3H8dc3k4hMhNQkbUMyM/YmfpJiqlK1VyWoWEIToSii0VpqK0KrVVQJgqCxSyaoNUGJklgbZBBrSxMyEaEihMg+mc/vj++dmJncc9dz77nL+/l4nMfMvefc7/mee2c+93u+qzMzRESk9HWIOgMiIpIfCvgiImVCAV9EpEwo4IuIlAkFfBGRMtEx6gwE6dGjh9XW1kadDRGRovLKK698ZmY94+0r2IBfW1tLQ0ND1NkQESkqzrnGoH2q0hERKRMK+CIiZUIBX0SkTCjgi4iUCQV8EZEyoYAvIlImFPCLXH091NZChw7+Z3191DkSkUJVsP3wJbn6ehg5EpYt848bG/1jgBEjosuXiBQmlfCL2OjR3wT7FsuW+edFRNpTwC9i8+al97yIlDcF/CJWXZ3e8yJS3kIJ+M65W51znzrn3grYv4dz7kvn3KzY9vswzlvuLr4YKivbPldZ6Z8XEWkvrBL+7cCgJMc8Z2bfj21/Cum8ZW3ECBg/HmpqwDn/c/x4NdiKSHyh9NIxs2edc7VhpCXpGTFCAV5EUpPPOvyBzrnXnXOPOee2jXeAc26kc67BOdewcOHCPGZNRKT05SvgvwrUmNkA4FrgoXgHmdl4M6szs7qePePO3y8iIhnKS8A3s6/M7OvY7/8AOjnneuTj3CIi4uUl4Dvnvuucc7Hfd4qdd1E+zi0iIl4ojbbOubuAPYAezrn5wB+ATgBmdiMwFBjlnGsClgPDzMzCOLeIiKQmrF46w5Psvw64LoxziYhIZjTSVkSkTCjgi4iUCQV8EZEyoYAvIlImFPBFRMqEAr6ISJlQwBcRKRMK+EVIC5eLSCa0iHmR0cLlIpIplfCLjBYuF5FMKeAXGS1cLiKZUsAvMlq4XEQypYBfZLRwuYhkSgG/gMXrjaOFy0UkU+qlU6CS9cZRgBeRdKmEX6Dy3RtHfftFSp9K+AUqn71x1LdfpDyohF+g8tkbJ1d3E7prECksCvgFKp+9cXJxN9Fy19DYCGbf3DXU1+uLQCQqCvg5EEZAy2dvnFzcTQTdNZx6avAXgYjkljOzqPMQV11dnTU0NESdjbS1rw8HXzIv5K6Tuchzhw4+oKeqpgbmzs3sXCLyDefcK2ZWF2+fSvghK8a5bnJxN5Hu3YGmhhDJPQX8kBXrXDcjRvgSdnOz/5nt3UhQG0RVVfzjNTWESO4p4IdMc914QXcNY8dqagiRqKgffsguvjh+fXg5BrREI4JHj/Z3PdXV/r0p1PYNkVKigB+ylsClgBZMU0OIRENVOjkQdn14vqmfvEhpCiXgO+dudc596px7K2C/c85d45yb7Zx7wzm3QxjnlfAlGjAlIsUtrBL+7cCgBPsHA1vFtpHADSGdVzK1eDHMnAl33QV/+xvccAOMG8dLp93Fdste5Dt8AviO9Mm6leqOQKQ4hFKHb2bPOudqExwyBLjT/CivF51z3Z1zvczs4zDOL4nV18Pl5yyi7/x/ckjXqezX+Um6fj4/7rHXtPp9Ab14ir15ir35R+N+1NZ+e532CE28JlI88lWHvynwYavH82PPteGcG+mca3DONSxcuDBPWSsOGZWim5t58rxpdD7657w8vxd3MZy9l07m0c8HchZ/ZWTPB3nkL2/BRx/BJ5/A//7HT3q9zf48wslcwzPszk95gts5lvn05vLGw/j7cVOpn9C89hTFONBMpGyZWSgbUAu8FbDvUeDHrR4/BeyYKL0dd9zRxJs40ayy0szXqvutstI/H9eaNWaTJplts40Z2GdsbGP4re3Ei9aBpoTprHuuZuvPLLuC020hVWZg73Xqa3bvvWZr1phzbfPVsjmXl7dGRNoBGiwgruarhD8f6NPqcW9gQZ7OXfRSLkWbwZQpMGAAHHEEdOrEL7iTTfmIM7iSl/khzVQkTKf1gCnP8QYDOJMxbMpHHEE9q1cDhx0GdXUM7/lk3DyX20AzkWKQr4A/BfhFrLfOzsCXVib192E0aKY0XUNjIxx4IAwZAitXwqRJ8PrrPFtzFCtZP630W7qVfhP0vVV05i6O4IDqN+HOO2HxYuo/3Yf6il/Qg2+q4Mp1oJlIwQsq+qezAXcBHwOr8aX544BfAb+K7XfAOGAO8CZQlyzNUqjSSbsqJkBNTfxqk5oa89U3Y8b4hCsr/e+rVyfMQ9x0Msn/8uVmF1xgTRWdbFGHKjuCequpSe/6Jk7053fO0n6tiKyLBFU6odXhh72VQsBPGKjTEBR477/2I7O99vJP7L+/2dy5ga9vyUv7OvdkX0ApBeS33zYbONAnePTRZkuWZHVdCvoimVPAj0iYDZrtA+/006eYVVX5CHnzzWbNzRmlE1pwXb3a7Pe/9wlvs43ZrFlJXxLWF6KIfCNRwNcCKDlUW+ur1tvLarGP5ma48EK46CL4/vf9wKnvfS/zTIZt+nQ48kj44gu44w7fuBsgaJEU5/xlikj6tABKREJfl/arr+Dgg32w/+UvYcaMvAb7lBqg99wTXn0Vtt8eDj8c/vCHwOitqaRF8iyo6B/1VgpVOmYhVqHMnWu27bZmFRVm116bchVOWNKub1+xwuzYY/2BQ4f6Bt5s0xSRpFAdfpGbNcusVy+z7t3NnnoqkixkVN/e3Gx2xRX+wF13Nfv883UOUS8dkXAlCviq0il0Tz0Fu+4KFRXw/POw116hJZ3OGIGgsQCNjQle6xyccYZvZ3jpJX8dH37Y5pBin0papJgo4BeyBx+EwYN9K++MGbDttqElne40yInq1ZNOoTxsGDz+uA/2u+wC772Xdf5FJH0K+IVq0qS10xfw3HPQu3eoyac76Vm8Buh4rw28a9hzT3jmGVixAnbbDd58c500NM2ySI4F1fVEvZV1Hf7NN/tK7T32SHkQU7oyGSPQegBX0Ja0Efbf/zbbZBOzjTc2e/nlNmmn24Cr+n+RdaFG2yJy003+Yxk0yGzZsoyTSRYMsxn0FPTaiooU05wzx2yzzcw23NBsxoyM8hPvC6LlS6z19epLQcqNAn6xuO02H5kGD/bdGjOUSmk5my6RQa8NKvXHvWuYN89siy3MunUz+9e/0r7jSOVOY9QodfuU8qOAXwwmTPDRbZ994vZZT0eqpeVsSr/xXpv2XcOHH5ptuaXZBhvYId95PvC18c4V9AWR0R2HSAlRwC90991n1qGDnwgthGqctEraIcrormH+fLOtt7ZV63ez3TvPSLmUXlWVPOBH9T6IRClRwFcvnag98QQMHw477+wXL+nSJaNkWnezDJLrKQtaL57inP85fnySvvWbbgrTptFp02/zRMUgDvhuQ5vX/uMf8XsTQeJeQ+CHLsSjqRukbAV9E0S9lUUJ/4UXfHF1wACzL77IKqlU6rQLuu563jzfkPutb5m9+urapxPV7Seb9ll1+FKOUAm/AL35Juy/vy/hTp0K3btnlVzQSFhIsaQdtT59YNo06NYN9tkH3n4bSDzBWssoXTOYMGHdO4vrr8/gjkOkhGl65CjMmwcDB/rf//WvddcSzEBOpmKOwpw5fgqG5mZ49lnqZ27NyJFtq3UqKxW4RYJoeuRCsmgR7LsvLF3qpxsIIdhDDqZijsoWW/j5g5qbYe+9GbHLXJXSRUKigJ9Py5f7hcbffx8mT4bttgst6YwaTAtV377wz3/C11/DXnsxYo+PNMGaSAgU8PNlzRq/EtSMGb5Lze67xz0sm/lkSmnmyfq3BjBk/aks+WAh/91sH+67YWHUWRIpegr4+XLWWfDAAzBmDAwdGveQdGewLFUt78OUT3biAB6h9+oP2PLX+/L3m76MOmsiRU2Ntvlw7bVwyilw8skwdqyvc4mjZBpes9T+fRjEY0xmCG90/gF1i56Arl0jy5tIoVOjbZQefhhOPRWGDIGrroob7FuqcYIGTSXqclmK2l/v4wzmCCax/coX4ZBDYOXKaDImUuQU8HNp1iw/inaHHXxUjzP0sxBGyBaaeNd7P0M5p+pmPzL5iCOgqSn/GRMpcgr4ubJgARxwAHzrW76UH1ANEW8hktaKsmtlloK6mH5/7LFw9dW+LeT4433rtIikrGPUGShJS5f67pdffunXoe3VK/DQZCNkL764uHvbZKLlekeP9u9PdXXr9+FUWLwYLrzQj04OqCYTkXWphJ9E2t0km5vh6KPh1Vf94t0DBiQ8PKi6pqWhtlSCfbrvY8Iupr//PZx2mm8A/9OfIs2nSFEJmmQnnQ0YBLwLzAbOibP/GGAhMCu2HZ8szXxPnhZvzvWMpvs9/3x/4JgxKZ+31Cf4ysk1rlljdswxPrGrry7cfIrkGbmcDx+oAOYAmwPrAa8D/dodcwxwXTrp5jPgB/2jB825HriARn29P+C448yam9M6fykvw5fNcorttX6vNq9ebY0/OMQndscdBZVPkajkOuAPBKa2enwucG67Ywo64CebWjiVBTQe++NLtoLO9jS72ZbVK0suaGcjkwXT44n3xdy9ywpbsO3efnmryZMLIp8iUUoU8MOow98U+LDV4/mx59o71Dn3hnPuPudcn3gJOedGOucanHMNCxfmbyh9uv3czdrW7z5w7UcMuPAgPmITDuV+Zs9bryxHyAZJNMVxOuL1aFq8vDM/+epB3/X18MPhmWcyy2SC/JRbt1gpXWEE/HhdJNoP330YqDWz/sCTwB3xEjKz8WZWZ2Z1PXv2DCFrqQn6h66qCl5VqWXag7tvW84WZx7EBraEn/Ewi+gB+MA0enSOMlxkwprJM+iL+d/zu/mlsTbfHH72M3jttUjzKVKowgj484HWJfbewILWB5jZIjNrGR55E7BjCOcNTdA/+tix38xAGc+yZUaX3xzHdqte4Qgm8Q7bttlfbiNkg4Q1k2fCEniPHn5QVvfuMGgQzJ4dWT5FClZQXU+qG74v//vAZnzTaLttu2N6tfr9YODFZOkWQi+d1uLV7/6OS83ALut+iRr78iClXjT//rdvbd9sM7MFCyLLq0hUyGWjrU+f/YD38L11Rsee+xNwYOz3S4G3Y18G04HvJUuz0Na0bd+wuz8P2xqcPVQ53CZOaE6pO1+p98bJh5Tew5dfNuva1ax//8C1gvVZSKnKecDPxVZoAb916bIvb9uXdLNX2MF6b7zUnPOFyqqq4ACiPt559sQTZp06me2+u9ny5W126bOQUqaAH5KJE8226/25vceW9on7jm3eaV7KQSNR10+VMHNk0iT/Bg8datbUtPZpfRZSyhIFfE2tkIYRP2/ijX7D2KpTIyd9+37eX922d2minjmJGnDLdaGTnBs+HK68Eu67z09Rbb7zmD4LKVcK+Ok491zfE2TcOB78dJe4hwQFk2R9udWNM0d++1s480wYNw4uvxzQZyHlSwE/VRMnwhVXwK9/DSeckPYgnXhdP9tTN84cuewyGDYMfvc7mDRJn4UUlLxO2BdU1xP1VlB1+DNnmnXu7BsAV60ys8wa/lp6hiSqP5YcWbHCf36dOplNm6bPQgpCLjoQoEbbLHz8sVnv3j4CfPppm12Zdu1TL5Fo3PO3L+w/nba1xWxoP+n1VuYzooqEJBcT9ingZ2rFCrMf/cisSxez114LNWn1A8+vlsDeh0ZbwHftA2qstssna4O+PguJQi4m7EsU8J3fX3jq6uqsoaEhugyYwYknwk03wT33+Im5pGi1XiR+Rxp4ht15i//j6D7T+c+8JBX6IjnS+u+ytZYFkDLhnHvFzOri7VOjbZAbb/TB/rzzFOxLQOtG2Feo4wgm8QNmcvGHR2ltXIlMvifsU8CP55ln4JRTYP/9Q19CT6LRvvfUFIZwBmM4lAfggguiyZSUvXxP2KcqnfYaG6Guzs+N/NJLsNFG+c+DZKW+ft0F0MEPqGo9n35lF2PWziey1fSbYMIEOPLIaDIsEiJV6aRq6VI46CBYvRomT1awL0L19T6wNzb6ZpiWkbMQpyR1k2Orx6+DPfaA44+HGTMizbtIrqmE38IMfv5zPwz/0Udh8OD8nVtCk1Ej2KJF8MMfwpIl0NAAfeIuyCZSFFTCT8Wll8K998Jf/qJgX8SCRsgmHDlbVQUPPwzLl8PBB/ufIiVIAR/8P/v55/uWkrPOijo3koWM16Xt29dPn/HKK74OqEDvfEWyUbIBP+X5Kd55xwf6HXf03TBdvCV6pVhk1c3twAPhj3/0gf/qq3OSP5EolWTAD2q4WyfoL1rk/8krK+HBB6FLl0jyK+HJupvb+ef7ap0zz4Tp03OaVylfeZ0wrZWSbLRNqeFu9Wq/2PXzz8PTT8PAgRnmVErOkiWw006+QPDqq9C7d9Q5khLSUiBt00W4Mrz+92XXaJtSw90ZZ8C0af5dVrCX1rp1gwce8I23hx0Gq1ZFnSMpIaNHtw32kL81GEoy4CdtuLvpJrj2Wh/0jz46b/mSItK3L9x2G7z4Ipx+etS5kRKSUU+ykJRkwE/YcPfMM3DSSb4657LLIsmfFImhQ79ZLeuuu6LOjZSIjHuShaAkA35gw93A9+HQQ2HLLeHuu6GiIuqsSqG75BLYZRdf6fruu1HnRkpAvidMa60kG23jWrLE19UvWAAvv+yDvkgq5s+H7beHXr38/ErqzSVZijffU1gTppVdo+061qyB4cPhP//xo2kV7CUdvXv7ydXefBNOPjnq3EgJGDHC9xhsbvY/czU7ZnvlEfDPPtvPj3PddbD33lHnRorRoEF+bYRbblF9vhSt0g/4N98MV17pS2a/+lXUuZFi9sc/+vr8E0+EOXOizo1I2kIJ+M65Qc65d51zs51z58TZ39k5d09s/0vOudowzpvU00/DqFGw774+6Itko2NHqK9n5ZoKZvUbTme3Kq+jJEWylXXAd85VAOOAwUA/YLhzrl+7w44DvjCzLYGrgPz0h1y9Gn7wA78mbceOeTmllLb652s4tulmvr9qJhdxfvC0HSIFKIwS/k7AbDN738xWAXcDQ9odMwS4I/b7fcDezuVhlrJ99oEXXghcyCSq+SykOMT7+xg9Gu5adSg3ciJnczk/4Z95GyUpkq0wAv6mwIetHs+PPRf3GDNrAr4Eqton5Jwb6ZxrcM41LFy4MISsETj7ZcoTrElZCvr7aJmj6XSu5B36cgdHszGL8jJKUiRbYQT8eBG1fef+VI7BzMabWZ2Z1fXs2TOErAWLcj4LKXxBfx8tY/WWU8kRTKIHn3ETJ1DdJ3fjWXQnKmEJI+DPB1qvCdcbWBB0jHOuI7AR8HkI585YlPNZSOEL+jtYs+abUZKv833O4xIO4UHu/umtOcmH7kQlTGEE/JnAVs65zZxz6wHDgCntjpkCtMxSNhSYZhEP8Y1yPgspfEF/By3TdLRM23F/9el80m8vdp50CsyeHXo+dCdafDK6I5s1Cw44AD77LLeZM7OsN2A/4D1gDjA69tyfgANjv68P3AvMBl4GNk+W5o477mi5NHGiWWWlmS83+a2y0j8vktbfx4cfmnXvbjZwoNnq1aHmw7m2eWjZnAv1NBKSjOLK//5nVl1ttummZgsWZJ0HoMGCYnXQjqi3XAd8M/8h1NT4f56aGgV7aSutv4/6ev/vdPHFoeahpiZ+wK+pCfU0EpK0P6+VK81+/GOzLl3MGhpCyUOigF8+k6eJ5JIZDBvmF055+WU/2VoIcr06koSrQwf/p9Cec37enDbM4IQT/HQdd98NP/95KHnQ5GkiueYc3HAD9OwJRx4JK1ZklVxLPfBRR/nJOauqMlyjV1IWRm+otNoGr7nGB/vzzw8t2CcVVPSPestHlY5I6B57zN/Dn3VWxkmofSn/wnrPU05n6lSzDh3MDjrIbM2a0K7DTHX4Ivl1wgm+4v+FFzJ6uert8y/M9zxp28+77/pG/u22M1uyJOu8t5co4KsOXyRsS5ZA//5+/qZZs6Br17RenlY9sIQib+/54sWw886waBHMnOnrjkKmOvxWNGpRcq5bN7j1Vt8v/9xz0365xojkX17e85aFmObMgfvvz0mwT6asAr5GLUre7LmnX4Ph2mth+vS0XhrlmqflKi/v+dlnw+OPw7hxsNtuISachqC6nqi3XNThq25U8mXiRLNt+iy199jS5lXU2t03p1dXqzEi+ZfT9/zWW32wOfnkEBOND9Xhe6oblXxo3Xd+F57nWXbjpo6j2OD2cepOWY5eeMHf8e2+Ozz2WM7X5lAdfozqRiUfWs9/8wI/ZiyncmLT9Txy+rRoMyb519gIBx/sB1AUwEJMZRHwWxpqGxvXnR4/Xj2dGnYlG+1n2hzNxbzHVlzy6XG+B4+Uh6+/hgMPhFWr4OGHYeONo85R6Qf81g214Kt0WoJ+vFGLatiVbLW/Y1xOJcdyGzU0wjnrLPkspai52Q+TfustX7L/3veizhFQBgE/3vSyZj7Yz5277hB1TUcr2YrX42NW5S68O+g0uP56ePrpSPIleXTBBfDQQ3DllbDvvlHnZq2SD/jpLnSihVEkWyNGtJ0zv6rKz4dT9/ifeb/Dlszd+5ds4JaqurBUTZwIl1ziJ0Y75ZSoc9NGyQf8dBtq1bArYRgxwt9BTpgAy5f7gZXLqOTo5lupbp7LJZyr6sIClnE73owZcPzxsMcecN11gWtqRyaov2bUW1j98NOdFEkTV0mY4o39uJpTzMB242mNAylAGceAxkazb3/bbIstzD77LC95jYdynzwt3QEVGvQiYYm3YlUlX9tsNrf/soVV8rVWryowiQZoBsaGr74y69/fbMMNzd55J7K8myngi0QmKHjsxtNmYFdxqkr4BSZoWcmWkn77x/V3NpkdcIBZRYWf9riVKAqPiQJ+ydfhi0QpXo8dgGfZnWs4mVO4hvFHPZf/jEmgoPa6ior4PfiW/vpseOQRzt/oWjoM+unaOv9C7OJdVlMriEShvt53650375uxN59/Dtv0XsrLK/vTrZuDN96I/80geRe0rGT7YA9wAuMZz4lc3/EUft00ts3xXbr4xvr2WrqE54qmVhDJUjajr1t67DQ3w2ef+a25Gf49ryvd7rnFT5d73nk5yrmkq3232pYBmjU1bY/7Cf/kek7iMQZzStOYNvuWLYsf7CHiLt5BdT1Rb6rDl0KR855bJ5/sE33mmZASlFxo/XfQj7dsMRvaG66/bcBXgXX+UczOi+rwRTKX89HXl14KW2wBxx4LS5eGlKiEraXkv2Pv//Eo+7Oioiuzr36EqppucY+vqiq8dQ0U8EWSSHX0dcbVPl27wm23wQcfaK6dAjfi4GU0bHIgtV0+5TsvPczBp/QJXDxl7Nj4VUORTpEdVPSPelOVjhSKVBbOCaXa57TT/AunTQv5CiQUTU1mQ4b4PpaTJ7fZVUhjd1A/fJHMpRLMQ1lNbelSs6239i/68stwL0Kyd+qp/kO95hozK6wg35oCvkiWkv1zBw3WSXsU7YwZZh06mP3ylyHlXEJx9dX+Az3tNDMr7ClYchbwgY2BfwL/jf38VsBxa4BZsW1KKmkr4EsxCXW95PPO8y+eMiWjvBRqybNo3XuvfzMPPthX61hhr4+dKOBn22h7DvCUmW0FPBV7HM9yM/t+bDswy3OKFJyghruMemT84Q8wYICfXvezz9J6aSGO7ixqzz0HRx4JP/qRfxMrKoDinUY924A/BLgj9vsdwEFZpidSlIIG62TUI2O99eDOO+GLL3zQt9RHw2fShVRLegZ45x2/RGFtLUye7IfOxhTtNOpBRf9UNmBxu8dfBBzXBDQALwIHJUhvZOy4hurq6hze9IgUgSuu8PUEt9yS8kvSbUso5LroSM2bZ9a7t9l3v2v2wQfr7C7k941s6vCBJ4G34mxD0gj4m8R+bg7MBbZIdl7V4UvZW7PGbM89zbp2NZs9O6WXpFu3HGZddMm0HSxaZNavn5/q+LXXAg8r1OvNKuAn2oB3gV6x33sB76bwmtuBocmOU8CXYpDzf/p588y6dzfbeWez1atTyk86Jc+wehcVYok3o89m6VKzgQPN1lvPbPr03GYwR3IZ8C8Hzon9fg7w1zjHfAvoHPu9B75HT79kaSvgS6HLW5C7+26f+AUXpJyvVANdWCX8Quu1ktFns3Kl2X77+Tfuvvtykqd83BHkMuBX4Xvn/Df2c+PY83XAzbHffwS8Cbwe+3lcKmkr4Euhy2uQO+YYHylCLnWG9aUV2jgECycwpr1qVVOT2bBh/qC//S39EyaRzzugnAX8XG4K+FLowgxySS1ZYrbNNmabbGK2cGGoSec6wKabl1x+AbWk1+Zxl2Z7b68T/YPLLkvvRCnKZ+FAAV8kB/JejfHaa75u+YADzJqbc3SSzIQVqDNaTzaNdCoq2j/XbH/hbP/gnHMyvv5k8lk4UMAXyYFIGirHjvUnuuKKHJ4kM2HcKaS7nmzQOYI+m/Zp/p4LzcDGMcpqqptz9tmphK+ALyUg713zmpv9EP+KCrPnnsvxyfIv9ZJ58oAZ77Npnf7Z/MUM7BaONceawC+RMD5j1eEr4ItkZvFisy239PX5//tf1LkJVaol80yrRFrSP5WrzMDqGW4daAr8EgkzUBd9L51cbgr4IgnMmmW2/vpme+21dkKvUpGsZJ5tlcjMI/3Ml/dxiHVkVcIvkULrbpqKRAFfK16JFKMBA+CGG2DaNDj33KhzE6rWi77PnesfJ5qcLq25gMaOpW7iaXDIIfyu+m6a6LTOIa3nwynWSdKCKOCLFKtjjoGTToLLL4eJE6POTU4FTU4HacwOetVVcNppcOihcPfd/PGSTklnOC3aSdKCBBX9o95UpSOSglWrzHbf3axzZ7OXX446N2vlq746pSqX5maziy7yO4YO9e9ZivksxCkjkkF1+CKFL+Mg+emn/gWbbGL20Ue5y2CK8hkkk/Zvb242+93v/JO/+EVK8xG1V6iTpAVRwBcpcFkHyddf97Nqbr+92Vdf5TSvyeSzoTPhuZqazE46yT8xapSffbQMJAr4qsMXKQCZLFzSRv/+cARwgKQAAAsFSURBVO+98MYbcPjhsHp16HlMVT4bOoMacy+9cCUMGwbXXw9nnw3jxvlW3TKnd0CkAIQSJAcPhhtvhMcfh1GjfGE3AmE2dCbrgROvMffWq79i+J2D4b77YMwYuOwyv1NUpSNSCEKtBjn/fP/i884LOZepCasOP6N05s0zGzDArGNHswkTsrqOYoXq8EUKW6gNnc3NZiec4BO5+OLQ85qKSGbgbGgw69XLrFs3s6lTM857sVPAFylA7YPiqFHpBcmEQbWpyWzECP8vftVVoeQv371T0pph8oEH/DdkdbXZm2/mN6MFRgFfpMBkW6JP6fWrV5sdeqjfec01ec1fGFIq4a9Z41cCA7OddjL7+OO4aUX95ZVPCvgiBSbbOvuUX79ypdlBB/mdf/7z2nn0kwXAQljcPOmXzhdfmO2/v99x7LFmy5dnlk6JUcAXKTDZLoiR1utXrzY76ih/wJln2sQJzUkDYKEsbh74ZTFzptnmm/vG2XHjEn6RFeMEaNlQwBcpMHkr4bdYs8bs1782A3ug6wjrzPKEry3Yxc2bm83GjDHr1MmsTx+z559fuyvXUysXi0QBX/3wRSKQaPbHMF+/th97xw7UPnwtsw77MwcvrWc6e/IdPmlzbOs+/9nmL16arTU2pjCzZXsffQT77w9nnOF/zpoFu+yydnfQ4LWKivjJFe0EaNkI+iaIelMJX0pdtg2JmU789YsN7revqbR59LYf8FJgqTso/TDWlk2reqe52ez228022sisSxez666Lu6ZvWMsjFjtUpSNSfoKCbVWV2c7rv2ZzqbZVdLSz+Yt17bImpQCYbp18vOODqnjipvHf/5oNHuwP2nVX/zjN6013AfRip4AvUoYSNbxOnGi2Xe/P7R4OMwP7uN9eZo2NSdPMpE4+UcNp4BfH0qVmo0ebrbeeH0g1dmzSyc/KrTdOEAV8kTKU8lzxt9ziI2Nlpdmll/qunAGy6b2TStDfonqV2Y03mm26qX9ixAizBQtSvuZyKskHSRTw1WgrUqJSanh1Dn75S3j7bdhnH79c4oABMGWKj8HtZDMxWrz8tFiPlRzN7Uyd9z341a98gs8+61fy6tUreeIx8ZZHlG8o4IuUqKBlAeMGwdpaeOgheOQRP7XykCGwww5w//0+esZk03undX5a9ORTzuci5lLL7RzLyk7dfB5eeAF23TWj65YEgor+qWzAYcDbQDNQl+C4QcC7wGzgnFTSVpWOSERWrfK9YrbaylerVFf76QtmzzazEKpNliyx50+qt8c67Ger6GgG9iiD7Wedp9rECev2vpH0kKs6fKAvsA3wdFDAByqAOcDmwHrA60C/ZGkr4IuEK+1A3dRkds89Zvvu+03lff/+Zr/9rdkjj/h5a+J0j2yjudnsk0/MnnzS7MILfU+bTp3MwL6u6mPXb/g768s7ZVvfnguJAr6zOPV06XLOPQ2caWYNcfYNBC40s31jj8+N3VlcmijNuro6a2hYJzkRyUB9PYwc2XZgUmVlgiqe9ubPh0mTYOpUX92ycqV/vls32Hpr6NkTunb124oVsHgxfPEFzJkDn3/uj3XOVxPtvTcccIAfNKVVqELnnHvFzOri7stDwB8KDDKz42OPjwJ+aGa/SZSmAr5IeGpr/ejW9mpqfONmWpYvhxdf9A29774L773ng/vSpX7r0gW6d4eNNvIn7tcP+vaFHXeEjTfO/mIkoUQBv2MKL34S+G6cXaPNbHIq54/zXNxvGefcSGAkQHVZjnsWyY1Q15nt0gX23NNvUlSSBnwz+0mW55gP9Gn1uDewIOBc44Hx4Ev4WZ5XRGKqq+OX8FWuKi/5qECbCWzlnNvMObceMAyYkofzikhMWJOhSXHLKuA75w52zs0HBgKPOuemxp7fxDn3DwAzawJ+A0wF/g383czezi7bItLa2lkxO8SfhTKtPvkZpC/FIZRG21xQo63Iuurr/TTA8+b56piWEnpWPXBSOGcu05dw5byXTi4o4Iu0FRR4u3SBRYvWPT6jHjhxhNrDR3Iuq146IlIYghb4aP9ci4x64KSRTljpS/5o1INIkUg3wIbVAyebCdNSpTaC/FDAFykSQQG2qiq3PXBy3cOnpaqqsdFP0NnY6B8nCvr6gshQ0JwLUW+aS0ekrUQLfIQ1D3y6yxqGcd50F1XRQieJoQVQREpDLhf4CGP5wkwCb7qLqmSy6lY5SRTw1UtHRID0e+OE1Xsn3XQ6dIi7NgvOtZm6v2wl6qWjOnwRAdLvjRNW75102wjy0YhcqhTwRQRIP5CGFXjTHQWsaSIyp4AvIkD6gTTMwJvOWrTZThNRzhTwRQRIP5BGGXi1WHlm1GgrIlJC1GgrIiIK+CIi5UIBX0SkTCjgi4iUCQV8EZEyoYAvIlImCrZbpnNuIRBnho209QA+CyGdYqHrLW263tIV1rXWmFnPeDsKNuCHxTnXENQntRTpekubrrd05eNaVaUjIlImFPBFRMpEOQT88VFnIM90vaVN11u6cn6tJV+HLyIiXjmU8EVEBAV8EZGyUTIB3zk3yDn3rnNutnPunDj7Ozvn7ontf8k5V5v/XIYnhes93Tn3jnPuDefcU865mijyGZZk19vquKHOOXPOFW1XvlSu1Tl3eOzzfds5NynfeQxTCn/L1c656c6512J/z/tFkc+wOOdudc596px7K2C/c85dE3s/3nDO7RDayYNWNy+mDagA5gCbA+sBrwP92h1zEnBj7PdhwD1R5zvH17snUBn7fVSpX2/suG7As8CLQF3U+c7hZ7sV8Brwrdjjb0ed7xxf73hgVOz3fsDcqPOd5TXvBuwAvBWwfz/gMcABOwMvhXXuUinh7wTMNrP3zWwVcDcwpN0xQ4A7Yr/fB+ztnHN5zGOYkl6vmU03s2Wxhy8CvfOcxzCl8vkCXAT8FViRz8yFLJVrPQEYZ2ZfAJjZp3nOY5hSuV4DNoz9vhGwII/5C52ZPQt8nuCQIcCd5r0IdHfO9Qrj3KUS8DcFPmz1eH7subjHmFkT8CVQlZfchS+V623tOHyJoVglvV7n3PZAHzN7JJ8Zy4FUPtutga2dcy845150zg3KW+7Cl8r1Xggc6ZybD/wDODk/WYtMuv/fKesYRiIFIF5JvX1/01SOKRYpX4tz7kigDtg9pznKrYTX65zrAFwFHJOvDOVQKp9tR3y1zh74O7fnnHP/Z2aLc5y3XEjleocDt5vZGOfcQGBC7Hqbc5+9SOQsVpVKCX8+0KfV496se9u39hjnXEf8rWGi26pClsr14pz7CTAaONDMVuYpb7mQ7Hq7Af8HPO2cm4uv95xSpA23qf4tTzaz1Wb2AfAu/gugGKVyvccBfwcwsxnA+viJxkpVSv/fmSiVgD8T2Mo5t5lzbj18o+yUdsdMAY6O/T4UmGaxFpIilPR6Y1Ucf8MH+2Ku44Uk12tmX5pZDzOrNbNafJvFgWbWEE12s5LK3/JD+EZ5nHM98FU87+c1l+FJ5XrnAXsDOOf64gP+wrzmMr+mAL+I9dbZGfjSzD4OI+GSqNIxsybn3G+AqfhW/1vN7G3n3J+ABjObAtyCvxWcjS/ZD4sux9lJ8XovBzYA7o21Tc8zswMjy3QWUrzekpDitU4FfuqcewdYA5xlZouiy3XmUrzeM4CbnHO/xVdtHFPEhTWcc3fhq+N6xNol/gB0AjCzG/HtFPsBs4FlwLGhnbuI3zcREUlDqVTpiIhIEgr4IiJlQgFfRKRMKOCLiJQJBXwRkTKhgC8iUiYU8EVEysT/A6QlKjwH73TkAAAAAElFTkSuQmCC\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "tester = Tester()\n",
    "tester.test()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
